用法研究所 - uv
What and Why
uv
是由 Astral 开发的 Python 工具。在一定程度上是可以取代 pip
、poetry
、pyenv
、twine
、virtualenv
等工具,主要用于做 Python 依赖管理和 Python 版本管理。通过 uv 命令可以完成从运行单个 Python 脚本、项目依赖管理(依赖声明和版本锁定)、虚拟环境管理等几乎所有维护 Python 项目需要的功能。
之前的工具都只负责部分功能,如 pyenv
负责系统上的 Python 版本管理;virtualenv
负责虚拟 Python 环境的创建;pip
负责依赖管理;uv
实现了所有这些功能。当然 poetry
也实现了这些功能,但 uv
说它比 poetry
更快。
为什么 uv 更快?
用 Rust 重写了包解析器;在包管理上完全脱离 Python 本身工具链,甚至不会启动 Python,在 Rust 层面处理问题;用了 Rust 相比 Python 就有了并发优势(Python 有 GIL 限制)。相比之下,像 poetry
这样的工具仍基于 Python 运行,受限于解释器启动时间、单线程执行等因素,会比较慢。
注意事项
uv
并不等同于pyenv
(用于管理系统中的多个 Python 版本)或twine
(用于将包发布到 PyPI),这些功能目前还不在 uv 的职责范围内。uv
只能管理通过uv run
运行时使用的 Python 版本。
Python 版本管理
当我们说 Python 版本管理时,我们就是在说 Python 可执行文件和标准库等完整配套的管理。先看使用方法
1 | 展示第一个选中的 Python 安装位置。一般来说这就是当前生效的 python 版本 |
确定 Python 版本 ref
我们用 uv run 运行脚本时,使用 uv add 安装依赖时,都需要用到 Python 环境,uv 按照如下规则确定使用哪个版本的 Python 环境。
- 当前目录下的 .python-version 文件指定的版本
- 父目录(不超过当前项目目录)下的 .python-version 文件指定的版本
- 用户目录下的 .python-version 文件指定的版本
- 如果都没有,则不指定,使用当前系统中生效的 Python 版本
发现 Python 版本 ref
在确定了 Python 版本后,uv 按照如下规则搜索符合版本的执行环境
- 首先尝试虚拟环境的发现规则
- 优先尝试 VIRTUAL_ENV 变量指定的虚拟环境
- 其次尝试 CONDA_PREFIX 指定的虚拟环境
- 最后尝试当前目录下的 .venv 或父目录下的 .venv 环境
- 然后尝试自己的发现规则
- 首先搜索 uv 自己的 Python 安装目录下的版本
- 其次检查系统中符合要求的 Python 版本
uv python find 得到的结果就是按照上述规则找到的第一个符合要求的 Python 版本路径。如果我们使用 uv python pin 改变当前目录下的 .python-version 文件所记录的版本,会发现 uv python find 得到的结果已经更新了。你可能会有疑问,之前创建的 venv 还是旧版本,uv run 会发生什么,答案是执行 uv run 时,uv 会将就得 venv 移除,创建符合新版本的 venv。下面的例子有展示
1 | 固定 3.10 版本 |
pyproject.toml 的 requires-python 的作用
.python-version 约束了当前文件夹下的固定的 Python 版本,而 pyproject.toml 下的 requires-python 约束了当前项目(其实也是当前文件夹)的 Python 版本。我们应该保持二者兼容,当不兼容时,执行 uv sync 或 uv run 等命令时会报错,如下
1 | uv run -- python -c "import sys; print(sys.executable)"; |
依赖管理
项目管理
uv run
uv tool 与 uvx
实践
新项目如何用 uv 管理
老项目如何引入 uv
自问自答
- uv add 安装的依赖位置在哪里?
- 一个 uv 项目中同时存在 requirements.txt 和 pyproject.toml 是最佳实践吗?